//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Linq;

using ProjectBase.Core;

using $prjsn$.Entity;
using $prjsn$.Common;
using $prjsn$.Common.Data;
using $prjsn$.Common.Business;
using ProjectBase.Core.Service;

namespace $safeprojectname$
{
    /// <summary>
    ///   All Business checks for 'FieldObject' on CRUD operations
    ///   are managed by: FieldObjectFacade
    /// </summary>
    public class FieldObjectFacade<TField, TDao> : BaseFacade<TField, int, FieldFilter, TDao>
        , IFieldObjectFacade<TField>
        where TField : FieldObject, new()
        where TDao : class, IFieldObjectDao<TField>
    {
        private static IDictionary<string, string> _dataTypeSet;

        #region constructor

        /// <summary>
        ///     appends Clear() to Change event
        /// </summary>
        static FieldObjectFacade()
        {
            ChangeHandler += Clear;
        }

        #endregion constructor

        #region IBaseFacade<T> override - FACTORY METHOD

        /// <summary>
        /// Factory Method pattern.
        /// A central and only point for creating new entity of the type TField.
        /// </summary>
        /// <returns>new entity 'TField' transient</returns>
        public override TField CreateNew()
        {
            var entity = new TField();

            // TODO preset entity
            return entity;
        }

        /// <summary>
        /// Needed for the BaseFacade checks on Update() and Delete().
        /// </summary>
        /// <returns></returns>
        public override FieldFilter CreateNewFilter()
        {
            var filter = base.CreateNewFilter();
            // TODO preset filter
            return filter;
        }

        #endregion IBaseFacade<T> override - FACTORY METHOD

        #region override Add

        public override TField Add(TField entity)
        {
            if (entity.Is())
            {
                if (entity.ColumnName.IsEmpty())
                {
                    entity.ColumnName = "P01_" + entity.PropertyName;
                }

                if (entity.DisplayName.IsEmpty())
                {
                    entity.DisplayName = entity.PropertyName.ToSentence();
                }
                entity.TableName = "[ems].[{0}Additional]".FormatWith(typeof(TField).Name.TrimEnd("Field"));
            }
            return base.Add(entity);
        }

        #endregion override Add

        #region IFieldBaseFacade

        public virtual IDictionary<string, string> GetDataTypes()
        {
            return DataTypeSet;
        }

        #endregion IFieldBaseFacade

        #region DataTypes

        protected static IDictionary<string, string> DataTypeSet
        {
            get
            {
                var dataTypeSet = _dataTypeSet;
                if (dataTypeSet.IsNull())
                {
                    dataTypeSet = GetDataTypeSet();
                    _dataTypeSet = dataTypeSet;
                }
                return dataTypeSet;
            }
            set { _dataTypeSet = value; }
        }

        protected static IDictionary<string, string> GetDataTypeSet()
        {
            // basic
            var dataTypes = new Dictionary<string, string>
            {
                {"String" , "Basic"},
                {"Int32", "Basic"},
                {"Decimal", "Basic"},
                {"Boolean", "Basic"},
                {"DateTime","Basic"},
            };

            // CustomLists
            var facade = Factory.CreateInstance<ICustomListTypeFacade>();
            facade.Change += ClearDataTypes;
            var customListTypes = facade.GetAll();
            foreach (var customListType in customListTypes.OrderBy(clt => clt.Description))
            {
                dataTypes.Add("CustomList." + customListType.Description, "CustomList");
            }

            // ICodeList, IBusinessObject
            var assembly = System.Reflection.Assembly.GetAssembly(typeof(FieldObject));
            var standardObjects = assembly
                .GetTypes()
                .Where(t => t.GetCustomAttributes(typeof(StandardObjectAttribute), false)
                             .IsNotEmpty()
                );
            foreach (var standardObject in standardObjects.OrderBy(t => t.Name))
            {
                dataTypes.Add(standardObject.Name, "StandardObject");
            }

            return dataTypes;
        }

        private static void ClearDataTypes(object sender, EventArgs e)
        {
            _dataTypeSet = null;
        }

        #endregion DataTypes

        #region Clear GetAll

        /// <summary>
        ///     Returns the set of all ICodeLists sorted by localized value.
        ///     Result is cached in the static list, enforcing great performance
        /// </summary>
        /// <returns></returns>
        public virtual IEnumerable<TField> GetAll()
        {
            var items = Items;
            if (items.IsNull())
            {
                items = Dao.GetAll().Select(c => c.Clone() as TField).ToList().AsReadOnly();
                Items = items;
            }

            return items.OrderBy(i => i.ToDisplay());
        }

        /// <summary>
        ///     Clears cached data when any change appear
        /// </summary>
        /// <param name = "sender"></param>
        /// <param name = "args"></param>
        private static void Clear(object sender, EventArgs args)
        {
            Items = null;
        }

        #endregion Clear GetAll

        #region properties

        /// <summary>
        ///     Cached collection of All CodeList values
        /// </summary>
        protected static IEnumerable<TField> Items { get; set; }
        public virtual ICustomListTypeFacade CustomListTypeFacade { protected get; set; }

        #endregion properties
    }
}